package TAIC.Classifier ;
import java.io.* ; 
import java.util.* ; 

import TAIC.test.TestMode;

public class Bayes extends Classifier {
	public static int MaxClass = TestMode.para.getParaInt( "MaxClass" ) ;
	public static int ImageMaxWords = 800 ; 
	String trainFile = null , testFile = null;
	Model model = new Model ( MaxClass, ImageMaxWords ) ;
	int classes , keys ;
	double p_w_c [][] ;  // p_w_c [ classss ][ keys ] ; 
	
	public static void print ( String str ) {
		System.out.println ( str ) ;
	}
	
	public static void main ( String argu [] ) {
		if ( argu.length != 2 ) {
			print ( "Please input the trainset and testset file names" ) ;
			return ;
		}
		Bayes bayes = new Bayes () ;
		bayes.train( argu [ 0 ] ) ;
		bayes.test( argu [ 1 ] ) ;
	}	

	public void train ( String trainFile ){
		double classWord [] = new double [ MaxClass ] ;  // total word in class i count 
		double classCount [] = new double [ MaxClass ] ; // instance count
		double [][] count = new double [ ImageMaxWords ][] ; // word w in class i count 
		double totalInstance = 0 ; 
		
		for ( int i = 0 ; i < ImageMaxWords ;  i ++ ) 
			for ( int j = 0 ; j < MaxClass ; j ++ ) model.wc [ i ][ j ] = 0.0 ;
		for ( int i = 0 ; i < MaxClass ; i ++ ) model.c [ i ] = 0.0 ;  
		
		try { 
			Scanner scanner ;
			if ( ! isPipe() )  scanner = new Scanner ( new File ( trainFile ) ) ;
			else {
				scanner = new Scanner ( new ByteArrayInputStream( trainPipe ) ) ;
			}
			Scanner picProb = new Scanner ( new File ( "picProb.txt" )) ;
			
			while ( scanner.hasNextLine() ) {
				double prob = picProb.nextDouble() ; 
				String buff = scanner.nextLine () ;
				Scanner strScanner = new Scanner ( buff ) ; 
				int classNo = translateClass ( strScanner.next ()) ;
				if ( classNo == -1 ) continue ; 
				classCount [ classNo ] += prob ; 
				totalInstance += prob ; 
				while ( strScanner.hasNext() ) {
					String temp = strScanner.next() ;
					int pos = temp.indexOf( ':' ) ;
					int word = Integer.valueOf( temp.substring( 0, pos )) - 1;
					double value = Integer.valueOf( temp.substring( pos +1 )) * prob ;
					if ( count [ word ] == null ) {
						count [ word ] = new double [ MaxClass ] ;
						classWord [ classNo ] += value  ;
						count [ word ][ classNo ] = value ;
					}
					else {
						classWord [ classNo ] += value  ;
						count [ word ][ classNo ] += value ;						
					}
				}				
			}
		}
		catch ( Exception e ) {
			print ( e.toString() ) ;
			e.printStackTrace() ; 
		}
		
		int totalWords = 0 ;
		for ( int i = 0 ; i < ImageMaxWords ; i ++ ) if ( count [ i ]!= null ) totalWords ++ ;
		for ( int i = 0 ; i < MaxClass ; i ++ ) model.c [ i ]=Math.log( (double) (1 + classCount [i]) / ( totalInstance+ MaxClass ) );
		for ( int i = 0 ; i < ImageMaxWords ; i ++ )  
			if ( count [ i ] != null ) 
			for ( int j = 0 ; j < MaxClass ; j ++ ) { 
				model.wc[i][j] = Math.log( (1+count[i][j])/(double)( classWord[j]+totalWords)) ;
			}
	}
	
	public double test ( String testFile ) {
		int correct = 0 ;
		int total = 0 ;
		try {
			Scanner scanner ;
			
			if ( ! isPipe() )  scanner = new Scanner ( new File ( testFile ) ) ;
			else {
				scanner = new Scanner ( new  ByteArrayInputStream ( testPipe ) ) ;
			}			
			
			while ( scanner.hasNextLine () ) {
				double result[] = new double [ MaxClass ] ;
				for ( int i = 0 ; i < MaxClass ; i ++ ) result [ i ] = model.c [ i ] ; 
//				System.out.println ( model.c[ 0 ]  ) ;
				String buff = scanner.nextLine () ;
				Scanner strScanner = new Scanner ( buff ) ; 
				int classNo = translateClass ( strScanner.next() ) ;
				while ( strScanner.hasNext() ) {
					String temp = strScanner.next() ;
					int pos = temp.indexOf( ':' ) ;
					int word = Integer.valueOf( temp.substring( 0, pos )) - 1;
					int value = Integer.valueOf( temp.substring( pos +1 )) ;
					for ( int j = 0 ; j < MaxClass ; j ++ ) 
						result [j] += value * model.wc [word][j] ;
				}
				int prediction = 0 ;
				for ( int i = 1 ; i < MaxClass ; i ++ ) 
					if ( result [ prediction ] < result [ i ]  ) prediction = i ;
//				System.out.println ( prediction ) ;				
				if ( prediction == classNo ) correct ++ ;
				total ++ ; 
			}
			//print ( "Final Accuracy on " + testFile + ": " + ((double)correct  / total )) ;
		}
		catch ( Exception e ) {
			print ( e.toString() ) ;
			e.printStackTrace() ; 
		}		
		if ( total == 0 ) return 0.0 ; else return (double)correct  / total  ; 
	}
	
	public boolean isPipe () {
		return false ;
	}
	
	protected int translateClass ( String str ) {
		return Integer.valueOf( str ) ;
	}
}
